package terminal.communication;

import java.net.BindException;
import java.util.HashMap;

import org.apache.log4j.Logger;

import terminal.ModulesManager;
import terminal.database.model.Node;
import core.communication.Client;
import core.communication.ClientChecker;
import core.communication.Direction;
import core.communication.message.VoteMessage;

public class CommunicationManager extends core.managers.CommunicationManager<Node, ModulesManager, MessageReceiver, MessageSender, InvocationHandler> {
	private static CommunicationManager	instance	= null;

	private HashMap<String, Client>		rkwClient	= null;

	public static CommunicationManager getInstance() throws BindException {
		if (instance == null)
			synchronized (CommunicationManager.class) {
				if (instance == null)
					instance = new CommunicationManager();
			}
		return instance;
	}

	private CommunicationManager() throws BindException {
		logger = Logger.getLogger("DEBUG");
		modulesManager = ModulesManager.getInstance();
		initializeNodes();
		invocationHandler = new InvocationHandler(this);
		setupServer(invocationHandler);
		initializeMessages();
		initializeClientChecker();
	}

	@Override
	protected void initializeMessagsThreads() {
		messageReceiver = new MessageReceiver("receiver", this);
		messageSender = new MessageSender("sender", this);
	}

	@Override
	protected void initializeNodes() {
		mainNode = modulesManager.getMainNode();
		Node rkw = modulesManager.getRKW();
		if (rkw != null) {
			prefferedParentURI = rkw.getLocatorURI();
			rkwClient.put(rkw.getLocatorURI(), new Client(rkw.getLocatorURI(), rkw.getNodeType()));
		}
	}

	@Override
	public HashMap<String, Client> getClients(Direction direction) {
		return rkwClient;
	}

	public void sendVote(String token, String vote) {
		VoteMessage message = new VoteMessage(token, vote, prefferedParentURI);
		send(message);
	}

	@Override
	protected void addTopClient(String locatorUri, Client client) {
		rkwClient.put(locatorUri, client);
	}

	@Override
	protected void addDownClient(String locatorUri, Client client) {
	}

	@Override
	public void deleteClient(String locatorUri) {
	}

	@Override
	public void editNode(String locatorUri, Node node) {
		if (locatorUri.compareTo(node.getLocatorURI()) != 0) {
			Client client = rkwClient.get(locatorUri);
			if (client != null) {
				client.getClient().disconnect();
				rkwClient.remove(locatorUri);
				rkwClient.put(node.getLocatorURI(), new Client(node.getLocatorURI(), node.getNodeType()));
			}
		}
		modulesManager.updateNode(locatorUri, node);
	}

	@Override
	protected void initializeClientChecker() {
		clientChecker = new ClientChecker<CommunicationManager>("clientChceker", this);
	}
}
